package com.apobates.forum.trident.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.apobates.forum.core.ad.ActiveDirectoryConnectorFactory;
import com.apobates.forum.core.api.ImageIOMeta;
import com.apobates.forum.core.api.service.BoardService;
import com.apobates.forum.core.api.service.BoardTopicCategoryIndexService;
import com.apobates.forum.core.api.service.PostsService;
import com.apobates.forum.core.api.service.TopicService;
import com.apobates.forum.core.api.service.TopicStatsService;
import com.apobates.forum.core.entity.BoardTopicCategoryIndex;
import com.apobates.forum.core.entity.Posts;
import com.apobates.forum.core.entity.Topic;
import com.apobates.forum.core.entity.TopicStats;
import com.apobates.forum.event.elderly.ActionEventCulpritor;
import com.apobates.forum.event.elderly.ForumActionEnum;
import com.apobates.forum.trident.OnlineDescriptor;
import com.apobates.forum.trident.exception.ForumValidateException;
import com.apobates.forum.trident.exception.MemberFreezeException;
import com.apobates.forum.trident.exception.ResourceNotFoundException;
import com.apobates.forum.trident.controller.form.PostsForm;
import com.apobates.forum.trident.controller.helper.ReportPlugTopic;
import com.apobates.forum.trident.digest.ForumReplierDigest;
import com.apobates.forum.member.MemberBaseProfile;
import com.apobates.forum.member.entity.MemberRoleEnum;
import com.apobates.forum.member.storage.core.MemberSessionBean;
import com.apobates.forum.strategy.Strategy;
import com.apobates.forum.strategy.StrategyEntityParam;
import com.apobates.forum.strategy.StrategyMode;
import com.apobates.forum.strategy.exposure.impl.TopicDetectionStrategy;
import com.apobates.forum.utils.Commons;
import com.apobates.forum.utils.DateTimeUtils;
import com.apobates.forum.utils.TipMessage;

/**
 * 话题回复控制器
 * 
 * @author xiaofanku
 * @since 20190306
 */
@Controller
@RequestMapping(value = "/posts")
public class PostsController {
	@Autowired
	private TopicService topicService;
	@Autowired
	private TopicStatsService topicStatsService;
	@Autowired
	private PostsService postsService;
	@Autowired
	private ImageIOMeta imageIOConfig;
	@Autowired
	private BoardService boardService;
	@Autowired
	private BoardTopicCategoryIndexService boardTopicCategoryIndexService;
	@Value("${site.pageSize}")
	private int pageSize;
	@Value("${site.domain}")
	private String siteDomain;
	@Value("${site.sensitive.dictionary}")
	private String sensitiveDictionary;
	
	@ModelAttribute("topicArg")
	public Topic getTopic(HttpServletRequest request){
		return ActiveDirectoryConnectorFactory.parseRefererToTopic(request.getHeader("referer"), siteDomain).orElse(null);
	}
	
	// 回复话题
	@GetMapping(path="/create")
	@OnlineDescriptor(action=ForumActionEnum.POSTS_REPLY)
	@Strategy(action=ForumActionEnum.POSTS_REPLY, mode=StrategyMode.WRITE, handler=TopicDetectionStrategy.class)
	public String createPostsForm(
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			@RequestParam(value = "qfloor", required = false, defaultValue = "0")long quoteFloorId, 
			@RequestParam(value = "qreplier", required = false, defaultValue = "0")long quotePostsId, 
			@RequestParam(value = "scale", required = false, defaultValue = "auto") String quoteImageScale, 
			@ModelAttribute("topicArg")Topic tpObj, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model)  {
		//--------------------------------------从Http Referer中获取需要的参数
		if(null == tpObj || tpObj.getId()<1){
			throw new ResourceNotFoundException("回复话题需要的参数解析失败");
		}
		//--------------------------------------对回复话题进行策略检查
		//  迁至StrategyInterceptorAdapter
		//--------------------------------------
		PostsForm form = new PostsForm();
		form.setBoard(tpObj.getBoardId()+"");
		form.setVolumes(tpObj.getVolumesId()+"");
		form.setTopic(tpObj.getId()+"");
		form.setToken(token); 
		if(quotePostsId > 0 && quoteFloorId > 0){
			//----------------------------------引用%d楼%s的回复
			Optional<Posts> data = postsService.get(quotePostsId);
			if(data.isPresent()){
				form.setContent(""); 
				//只在移动设备中使用
				form.setQuoteFloor(quoteFloorId);
				form.setQuoteId(quotePostsId);
				form.setQuoteScale(quoteImageScale);
				model.addAttribute("infoTip", String.format("引用%d楼%s的回复", quoteFloorId, data.get().getMemberNickname()));
			}
		}
		model.addAttribute("form", form);
		//
		Topic topic = topicService.get(tpObj.getId()).orElse(Topic.empty(tpObj.getVolumesId(), tpObj.getBoardId()));
		topic.setBoard(boardService.get(tpObj.getBoardId(), tpObj.getVolumesId()));
		model.addAttribute("topic", topic);
		return "default/posts/create";
	}
	//引用回复时,引用的内容
	private String quoteContent(Optional<Posts> quotePosts){
		if(!quotePosts.isPresent()){
			return "";
		}
		Posts p = quotePosts.get();
		String t ="<blockquote><strong>引用<a href=\"%s\">%s</a> %s 发表于 %s 的回复</strong><br/>%s</blockquote>";
		String quoteUrl = String.format("%s/topic/%s.xhtml#posts-%d", siteDomain, ActiveDirectoryConnectorFactory.generateConnectString(p.getVolumesId(), p.getBoardId(), p.getTopicId()), p.getId());
		String quoteContent = (p.isNormal())?p.getContent():"<p>回复内容已被屏蔽</p>";
		return String.format(t, 
								quoteUrl, 
								p.getFloorNumber()+"楼", 
								p.getMemberNickname(), 
								DateTimeUtils.getRFC3339(p.getEntryDateTime()), 
								quoteContent);
	}
	//前补引用的内容
	private String getRealPostsContent(long quotePostsId, String formPostsContent, String imageScale, HttpServletRequest request){
		String postsContent = formPostsContent;
		//
		if(quotePostsId > 0){
			String quotePostsContent = quoteContent(postsService.getPostsContentForQuote(quotePostsId, imageIOConfig, false, imageScale, request.getServletContext().getRealPath("/WEB-INF/"+sensitiveDictionary)));
			postsContent = quotePostsContent + postsContent;
		}
		return postsContent;
	}
	
	@PostMapping(path="/create")
	@OnlineDescriptor(action=ForumActionEnum.POSTS_REPLY)
	@Strategy(action=ForumActionEnum.POSTS_REPLY, param=StrategyEntityParam.QUERY_STR, paramId="topic", mode=StrategyMode.WRITE, handler=TopicDetectionStrategy.class)
	public String createPostsAction(
			@ModelAttribute("form") PostsForm form, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		ActionEventCulpritor aec = ActionEventCulpritor.getInstance(mbean.getMid(), mbean.getNickname(), request, form.getToken());
		//----------------------------------对回复话题进行策略检查
		//  迁至StrategyInterceptorAdapter
		//----------------------------------
		if(!Commons.isNotBlank(form.getContent())){
			throw new ForumValidateException("话题回复内容不可以为空");
		}
		//----------------------------------引用%d楼%s的回复
		String postsContent = getRealPostsContent(form.getQuoteId(), form.getContent(), form.getQuoteScale(), request);
		//----------------------------------
		long boardId = form.getLongBoard();
		int volumesId = form.getIntegerVolumes(); 
		long topicId = form.getLongTopic();
		//
		if(boardId>0 && volumesId>=0 && topicId>0) {
			boolean data = postsService.create(
					volumesId, 
					boardId, 
					topicId, 
					postsContent, 
					imageIOConfig, 
					aec)>0;
			if(data) {
				//----------------------------------
				// 回复通知(tc.notify)
				//----------------------------------
				TopicStats topicStats = topicStatsService.getByTopic(topicId).orElse(new TopicStats(topicId, volumesId, boardId));
				return String.format("redirect:/topic/%s.xhtml?p=%d", ActiveDirectoryConnectorFactory.generateConnectString(volumesId, boardId, topicId), topicStats.getTopicPageSize(pageSize));
			}
		}
		model.addAttribute("form", form);
		//
		Topic topic = topicService.get(topicId).orElse(Topic.empty(volumesId, boardId));
		topic.setBoard(boardService.get(boardId, volumesId));
		model.addAttribute("topic", topic);
		//
		model.addAttribute("errors", "话题回复操作失败");
		return "default/posts/create";
	}
	
	// 编辑回复,只允许针对Posts.reply(回复的内容/非话题的内容/)的记录
	@GetMapping(path="/edit")
	@OnlineDescriptor(action=ForumActionEnum.POSTS_EDIT)
	@Strategy(action=ForumActionEnum.POSTS_EDIT, param=StrategyEntityParam.QUERY_STR, paramId="id", allowRoles={MemberRoleEnum.ADMIN, MemberRoleEnum.MASTER, MemberRoleEnum.BM})
	public String editPostsForm(
			@RequestParam("id")long postsId, 
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model){
		Posts posts = postsService.getPostsContentForEdit(postsId, imageIOConfig).orElse(Posts.empty(""));
		//----------------------------------策略检查开始,不作具体限制让策略去作
		//  迁至StrategyInterceptorAdapter
		//----------------------------------策略检查结束
		PostsForm form = new PostsForm();
		form.setRecord(postsId);
		form.setBoard(posts.getBoardId()+"");
		form.setTopic(posts.getTopicId()+"");
		form.setContent(posts.getContent());
		form.setVolumes(posts.getVolumesId()+"");
		form.setToken(token); 
		model.addAttribute("form", form);
		//
		Topic topic = topicService.get(posts.getTopicId()).orElse(Topic.empty(posts.getVolumesId(), posts.getBoardId()));
		topic.setBoard(boardService.get(posts.getBoardId(), posts.getVolumesId()));
		model.addAttribute("topic", topic);
		return "default/posts/modify";
	}
	@PostMapping(path="/edit")
	@OnlineDescriptor(action=ForumActionEnum.POSTS_EDIT)
	@Strategy(action=ForumActionEnum.POSTS_EDIT, param=StrategyEntityParam.QUERY_STR, paramId="record", allowRoles={MemberRoleEnum.ADMIN, MemberRoleEnum.MASTER, MemberRoleEnum.BM})
	public String editPostsAction(@ModelAttribute("form")PostsForm form, MemberSessionBean mbean, HttpServletRequest request, Model model){
		ActionEventCulpritor aec = ActionEventCulpritor.getInstance(mbean.getMid(), mbean.getNickname(), request, form.getToken());
		//----------------------------------策略检查开始,不作具体限制让策略去作
		//  迁至StrategyInterceptorAdapter
		//----------------------------------策略检查结束
		boolean status = postsService.edit(
				form.getLongRecord(), 
				form.getContent(), 
				imageIOConfig, 
				aec).orElse(false);
		if(status){
			return String.format("redirect:/topic/%s.xhtml", ActiveDirectoryConnectorFactory.generateConnectString(form.getIntegerVolumes(), form.getLongBoard(), form.getLongTopic())); //?20191104
		}
		//
		model.addAttribute("errors", "编辑话题回复操作失败");
		model.addAttribute("form", form);
		//
		Topic topic = topicService.get(form.getLongTopic()).orElse(Topic.empty(form.getIntegerVolumes(), form.getLongBoard()));
		topic.setBoard(boardService.get(form.getLongBoard(), form.getIntegerVolumes()));
		model.addAttribute("topic", topic);
		return "default/posts/modify";
	}
	//话题内容页中关于回复的功能
	// 快速回复
	@PostMapping(path = "/reply", produces = "application/json;charset=UTF-8")
	@ResponseBody
	@OnlineDescriptor(action=ForumActionEnum.POSTS_REPLY, isAjax=true)
	@Strategy(action=ForumActionEnum.POSTS_REPLY, mode=StrategyMode.WRITE, handler=TopicDetectionStrategy.class)
	public String quickReplyAction(
			@RequestParam("content") String content, 
			@RequestParam(value = "quote", required = false, defaultValue = "0")long quotePostsId, 
			@RequestParam(value = "scale", required = false, defaultValue = "auto")String imageScale, 
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) throws MemberFreezeException {
		//----------------------------------从Http Referer中获取需要的参数
		Optional<Topic> tpObj = ActiveDirectoryConnectorFactory.parseRefererToTopic(request.getHeader("referer"), siteDomain);
		if(!tpObj.isPresent()){
			return TipMessage.ofError("操作参数解析失败").toJsonString();
		}
		Topic t = topicService.get(tpObj.get().getId()).orElseThrow(()->new ResourceNotFoundException("话题不存在或暂时无法访问"));
		long topicId = t.getId(); 
		long boardId = t.getBoardId(); 
		int boardGroupId = t.getVolumesId();
		ActionEventCulpritor aec = ActionEventCulpritor.getInstance(mbean.getMid(), mbean.getNickname(), request, token);
		//----------------------------------对回复话题进行策略检查
		//  迁至StrategyInterceptorAdapter
		//----------------------------------
		if(!Commons.isNotBlank(content)){
			return TipMessage.ofError("话题回复内容不可以为空").toJsonString();
		}
		//----------------------------------引用%d楼%s的回复
		String postsContent = getRealPostsContent(quotePostsId, content, imageScale, request);
		//----------------------------------
		if(boardId>0 && boardGroupId>=0 && topicId>0) {
			long postsId = postsService.create(boardGroupId, boardId, topicId, postsContent, imageIOConfig, aec); //这里有图片会出问题吗?@20200506
			if(postsId>0) {
				//异步
				Posts posts = postsService.get(postsId).orElse(null);
				if(null == posts){
					return TipMessage.ofError("回复失败").toJsonString();
				}
				return new ForumReplierDigest(
								postsId, 
								posts.getMemberId(), 
								posts.getMemberNickname(), 
								mbean.getGroup().getTitle(), 
								MemberBaseProfile.getStyle(mbean.getGroup(), mbean.getRole()), 
								mbean.getSignature(), 
								posts.getEntryDateTime(), 
								postsContent, 
								posts.getFloorNumber(), 
								t.getMemberId() == mbean.getMid(), 
								false, 
								"-1", 
								null).toJsonString();
			}
		}
		return TipMessage.ofError("回复失败").toJsonString();
	}
	
	// 删除回复|屏弊回复
	@PostMapping(path = "/delete", produces = "application/json;charset=UTF-8")
	@ResponseBody
	@OnlineDescriptor(action=ForumActionEnum.POSTS_DEL, isAjax=true)
	@Strategy(action=ForumActionEnum.POSTS_DEL, param=StrategyEntityParam.QUERY_STR, paramId="id", allowRoles={MemberRoleEnum.ADMIN, MemberRoleEnum.MASTER, MemberRoleEnum.BM})
	public TipMessage removePostsAction(
			@RequestParam("id") long postsId, 
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			@ModelAttribute("topicArg")Topic tpObj, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		//----------------------------------从Http Referer中获取需要的参数
		if(null == tpObj || tpObj.getId()<1){
			return TipMessage.ofError("操作参数解析失败");
		}
		//----------------------------------
		ActionEventCulpritor aec = ActionEventCulpritor.getInstance(mbean.getMid(), mbean.getNickname(), request, token);
		//----------------------------------策略检查开始,限制角色:管理员,版主,大版主都可以
		//  迁至StrategyInterceptorAdapter
		//----------------------------------策略检查结束
		boolean symbol = postsService.remove(postsId, aec).orElse(false); 
		if (symbol) {
			return TipMessage.ofSuccess("话题回复成功删除");
		}
		return TipMessage.ofError("操作失败");
		
	}
	
	// 举报
	@PostMapping(path = "/report", produces = "application/json;charset=UTF-8")
	@ResponseBody
	@OnlineDescriptor(action=ForumActionEnum.POSTS_REPORT, isAjax=true)
	@Strategy(action=ForumActionEnum.POSTS_REPORT, param=StrategyEntityParam.QUERY_STR, paramId="id")
	public TipMessage reportPostsAction(
			@RequestParam("id") long postsId, 
			@RequestParam("type")int reportTypeSymbol, 
			@RequestParam("reason")String reportContent, 
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			@ModelAttribute("topicArg")Topic tpObj, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		//----------------------------------从Http Referer中获取需要的参数
		if(null == tpObj || tpObj.getId()<1){
			return TipMessage.ofError("操作参数解析失败");
		}
		long topicId = tpObj.getId(); 
		//----------------------------------
		Posts posts = postsService.get(postsId, topicId);
		ActionEventCulpritor aec = ActionEventCulpritor.getInstance(mbean.getMid(), mbean.getNickname(), request, token);
		//----------------------------------策略检查开始,不限制角色
		//  迁至StrategyInterceptorAdapter
		//----------------------------------策略检查结束
		Optional<BoardTopicCategoryIndex> btc = boardTopicCategoryIndexService.getReportRelativeRecord();
		if (!btc.isPresent()) {
			return TipMessage.ofError("未知的存储目标");
		}
		Optional<Topic> result = topicService.plug(new ReportPlugTopic(ForumActionEnum.POSTS_REPORT, aec, posts, reportTypeSymbol, reportContent, btc.get()));
		if (result.isPresent()) {
			return TipMessage.ofSuccess("回复举报成功");
		}
		return TipMessage.ofError("操作失败");
	}
	
	// 返回引用的回复内容
	@GetMapping(path = "/quote/data.json", produces = "application/json;charset=UTF-8")
	@ResponseBody
	@Strategy(action=ForumActionEnum.POSTS_QUOTE, param=StrategyEntityParam.REFERER, mode=StrategyMode.WRITE, handler=TopicDetectionStrategy.class)
	public Map<String,String> quotePostsContent(
			@RequestParam("id")long postsId, 
			@RequestParam(value = "scale", required = false, defaultValue = "auto") String imageScale, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model){
		//----------------------------------从Http Referer中获取需要的参数
		Optional<Topic> tpObj = ActiveDirectoryConnectorFactory.parseRefererToTopic(request.getHeader("referer"), siteDomain);
		if(!tpObj.isPresent()){
			return TipMessage.ofError("操作参数解析失败").toMap();
		}
		//----------------------------------
		Optional<Posts> data = postsService.get(postsId);
		if(!data.isPresent()){
			return TipMessage.ofError("操引用的回复对象不存在或暂时无法访问").toMap();
		}
		Posts p = data.get();
		//----------------------------------对回复话题进行策略检查
		//  迁至StrategyInterceptorAdapter
		//----------------------------------引用%d楼%s的回复
		Map<String,String> rs = new HashMap<>();
		rs.put("quote", postsId+"");
		rs.put("scale", imageScale);
		rs.put("infoTip", String.format("引用%d楼%s的回复", p.getFloorNumber(), p.getMemberNickname()));
		//----------------------------------
		return rs;
	}
	
	// 快速回复的表单
	@GetMapping(path="/reply/form")
	@Strategy(action=ForumActionEnum.POSTS_REPLY_FORM, param=StrategyEntityParam.REFERER, mode=StrategyMode.WRITE, handler=TopicDetectionStrategy.class)
	public String getQuickReplyForm(
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			@ModelAttribute("topicArg")Topic tpObj, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model){
		//----------------------------------对回复话题进行策略检查
		//  迁至StrategyInterceptorAdapter
		//----------------------------------
		model.addAttribute("token", token);
		model.addAttribute("member", MemberBaseProfile.init(mbean.toMember()).toMap());
		return "default/posts/reply_embedded";
	}
}
